#include <memory>
#include <sys/epoll.h>
#include "socket.hpp"

class server{
public:
    server(uint16_t port):_port(port){
    }
    void init(){
        _listenfd=std::make_unique<TcpSocket>(_port);   //创建listen套接字
        _isrunning=true;
        _listenfd->BulitTcpSocket(_port);               //bind,listen等操作
        _epfd=epoll_create(256);                        //创建epoll模型
        struct epoll_event listen_ev;                   //_listenfd的对应事件
        listen_ev.events=EPOLLIN;
        listen_ev.data.fd=_listenfd->Fd();
        //将listen套接字添加进epoll模型
        int n=epoll_ctl(_epfd,EPOLL_CTL_ADD,_listenfd->Fd(),&listen_ev);
        if(n==-1){
            LOG(ERROR)<<"epoll_ctl error:"<<strerror(errno);
            exit(1);
        }
    }
    void start(){
        while(_isrunning){
            //获取epoll当中的就绪事件
            int n=epoll_wait(_epfd,revents,_rent_num,-1);
            switch (n)
            {
            case 0:
                LOG(INFO)<<"no I/O aready";//没有I/O事件发生
                break;
            case -1:
                LOG(ERROR)<<"select error:"<<strerror(errno);
                break;
            default:
                //处理I/O事件
                handle_rfds();
                break;
            }
        }
    }
private:
    void handle_rfds(){
        //处理就绪的I/O事件
        for(int i=0;i<_rent_num;i++){
            if(revents[i].data.fd==_listenfd->Fd()){//如果待处理IO事件的是listen套接字
                //获取连接
                inetaddr client;
                int newfd=_listenfd->accept(&client);
                LOG(INFO)<<"获取了一个新链接:"<<client.addr();
                //将新链接设置进epoll模型中
                struct epoll_event event;
                event.events=EPOLLIN;
                event.data.fd=newfd;
                int n=epoll_ctl(_epfd,EPOLL_CTL_ADD,newfd,&event);
                if(n==-1){
                    LOG(ERROR)<<"set a new fd fail"<<strerror(errno);
                }
            }
            else if(revents[i].events==EPOLLIN){//如果待处理IO事件的fd是用户连接
                //读取用户请求
                char in_buffer[2048];
                int fd=revents[i].data.fd;
                int n=recv(fd,in_buffer,sizeof(in_buffer),0);
                if(n==0){//如果用户请求断开连接
                    LOG(INFO)<<"client :"<<fd<<" 断开了链接";
                    epoll_ctl(_epfd,EPOLL_CTL_DEL,fd,nullptr);
                    close(fd);
                }
                else if(n>0){//处理用户请求
                    in_buffer[n]='\0';
                    std::cout<<"client["<<fd<<"] say#"<<in_buffer<<std::endl;
                    std::string recv_mesg="echo#";
                    recv_mesg+=in_buffer;
                    send(fd,recv_mesg.c_str(),recv_mesg.size(),0);
                }
                if(n==-1){//获取请求失败
                    LOG(ERROR)<<"fd :"<<i<<"is error"<<strerror(errno);
                    epoll_ctl(_epfd,EPOLL_CTL_DEL,revents[i].data.fd,nullptr);
                    close(i);
                }
            }
        }
    }
    std::unique_ptr<Socket> _listenfd;
    uint16_t _port;
    struct epoll_event revents[64];
    int _rent_num=64;
    int _epfd;
    bool _isrunning;
};